package com.ljx.singleMode;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 内部类单例模式（变相懒加载）
 * 基于JVM类加载 保证线程安全
 * @作者 LJX
 * @日期 2022/12/9 16:37
 */
public class InnerClassSingletonTest {

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {

//        InnerClassSingleton instance = InnerClassSingleton.getInstance();
//        InnerClassSingleton hs = InnerClassSingleton.getInstance();
//        System.out.println(instance == hs);

        //多线程依旧没有问题
//        for (int i = 0; i < 10; i++) {
//            new Thread(() -> {
//                InnerClassSingleton ls = InnerClassSingleton.getInstance();
//                System.out.println(ls);
//            }).start();
//        }


        //通过反射破坏可以单例
        InnerClassSingleton instance = InnerClassSingleton.getInstance();

//        Constructor<InnerClassSingleton> declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();
//        declaredConstructor.setAccessible(Boolean.TRUE);
//        InnerClassSingleton innerClassSingleton = declaredConstructor.newInstance();
//        System.out.println(innerClassSingleton == instance);

        //通过序列化也可以入侵单例
//        ObjectOutputStream testSerializable = new ObjectOutputStream(new FileOutputStream("testSerializable"));
//        testSerializable.writeObject(instance);
//        testSerializable.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("testSerializable"));
        InnerClassSingleton innerClassSingleton = (InnerClassSingleton) ois.readObject();
        System.out.println(innerClassSingleton == instance);

    }

}

class InnerClassSingleton implements Serializable {

    static final long serialVersionUID = 3333653159882806257L;

    String ss = "";

    private static class InnerClassHolder{
        private static InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }

    private InnerClassSingleton(){
        if(null != InnerClassHolder.INSTANCE){
            throw new RuntimeException("单例不允许多个实例");
        }
    }

    public static InnerClassSingleton getInstance(){
        return InnerClassHolder.INSTANCE;
    }

    /**
     * 解决序列化破坏单例模式方法
     * @return
     * @throws ObjectStreamException
     */
    Object readResolve() throws ObjectStreamException{
        return InnerClassHolder.INSTANCE;
    }

}